Package g4p_controls

Source Code of g4p_controls.GTextArea

/*
  Part of the GUI for Processing library
    http://www.lagers.org.uk/g4p/index.html
  http://gui4processing.googlecode.com/svn/trunk/

  Copyright (c) 2012 Peter Lager

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/

package g4p_controls;

import g4p_controls.HotSpot.HSrect;
import g4p_controls.StyledString.TextLayoutHitInfo;
import g4p_controls.StyledString.TextLayoutInfo;

import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.font.TextHitInfo;
import java.awt.font.TextLayout;
import java.awt.geom.GeneralPath;
import java.util.LinkedList;

import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PGraphicsJava2D;
import processing.event.MouseEvent;

/**
* The text area component. <br>
*
* This control allows the user to enter and edit multiple lines of text. The control
* also allows default text, horizontal and vertical scrollbars.
*
* Enables user text input at runtime. Text can be selected using the mouse
* or keyboard shortcuts and then copied or cut to the clipboard. Text
* can also be pasted in.
*
* @author Peter Lager
*
*/
public class GTextArea extends GEditableTextControl {

  private static float pad = 6;

  /**
   * Create a text area without scrollbars and a text wrap width to fit the control.
   *
   * @param theApplet
   * @param p0
   * @param p1
   * @param p2
   * @param p3
   */
  public GTextArea(PApplet theApplet, float p0, float p1, float p2, float p3) {
    this(theApplet, p0, p1, p2, p3, SCROLLBARS_NONE, Integer.MAX_VALUE);
  }

  /**
   * Create a text field with the given scrollbar policy and a text wrap width to fit the control. <br>
   * The scrollbar policy can be one of these <br>
   * <ul>
   * <li>SCROLLBARS_NONE</li>
   * <li>SCROLLBARS_HORIZONTAL_ONLY</li>
   * <li>SCROLLBARS_VERTICAL_ONLY</li>
   * <li>SCROLLBARS_BOTH</li>
   * </ul>
   * If you want the scrollbar to auto hide then perform a logical or with
   * <ul>
   * <li>SCROLLBARS_AUTOHIDE</li>
   * </ul>
   * e.g. SCROLLBARS_BOTH | SCROLLBARS_AUTOHIDE
   * <br>
   * @param theApplet
   * @param p0
   * @param p1
   * @param p2
   * @param p3
   * @param sbPolicy
   */
  public GTextArea(PApplet theApplet, float p0, float p1, float p2, float p3, int sbPolicy) {
    this(theApplet, p0, p1, p2, p3, sbPolicy, Integer.MAX_VALUE);
  }

  /**
   * Create a text field with the given scrollbar policy with a user specified text wrap length <br>
   *
   * @param theApplet
   * @param p0
   * @param p1
   * @param p2
   * @param p3
   * @param sbPolicy
   */
  public GTextArea(PApplet theApplet, float p0, float p1, float p2, float p3, int sbPolicy, int wrapWidth) {
    super(theApplet, p0, p1, p2, p3, sbPolicy);
    children = new LinkedList<GAbstractControl>();
    tx = ty = pad;
    tw = width - 2 * pad - ((scrollbarPolicy & SCROLLBAR_VERTICAL) != 0 ? 18 : 0);
    th = height - 2 * pad - ((scrollbarPolicy & SCROLLBAR_HORIZONTAL) != 0 ? 18 : 0);
    this.wrapWidth = (wrapWidth == Integer.MAX_VALUE) ? (int)tw : wrapWidth;
    // Clip zone
    gpTextDisplayArea = new GeneralPath();
    gpTextDisplayArea.moveTo( 00);
    gpTextDisplayArea.lineTo( 0, th);
    gpTextDisplayArea.lineTo(tw, th);
    gpTextDisplayArea.lineTo(tw,  0);
    gpTextDisplayArea.closePath();

    // The image buffer is just for the typing area
    buffer = (PGraphicsJava2D) winApp.createGraphics((int)width, (int)height, PApplet.JAVA2D);
    buffer.rectMode(PApplet.CORNER);
    buffer.g2.setFont(localFont);
    hotspots = new HotSpot[]{
        new HSrect(1, tx, ty, tw, th),      // typing area
        new HSrect(9, 0, 0, width, height)    // control surface
    };
    G4P.pushStyle();
    G4P.showMessages = false;
    z = Z_STICKY;
    G4P.control_mode = GControlMode.CORNER;
    if((scrollbarPolicy & SCROLLBAR_HORIZONTAL) != 0){
      hsb = new GScrollbar(theApplet, 0, 0, tw, 16);
      addControl(hsb, tx, ty + th + 2, 0);
      hsb.addEventHandler(this, "hsbEventHandler");
      hsb.setAutoHide(autoHide);
    }
    if((scrollbarPolicy & SCROLLBAR_VERTICAL) != 0){
      vsb = new GScrollbar(theApplet, 0, 0, th, 16);
      addControl(vsb, tx + tw + 18, ty, PI/2);
      vsb.addEventHandler(this, "vsbEventHandler");
      vsb.setAutoHide(autoHide);
    }
    G4P.popStyle();
    setText("", (int)tw);
//    z = Z_STICKY;
    createEventHandler(G4P.sketchApplet, "handleTextEvents",
        new Class<?>[]{ GEditableTextControl.class, GEvent.class },
        new String[]{ "textcontrol", "event" }
    );
    registeredMethods = PRE_METHOD | DRAW_METHOD | MOUSE_METHOD | KEY_METHOD;
    G4P.addControl(this);
  }

  /**
   * Set the default text for this control. If provided this text will be
   * displayed in italic whenever it is empty. It will also be wrapped to the control size.
   * @param dtext
   */
  public void setDefaultText(String dtext){
    if(dtext == null || dtext.length() == 0)
      defaultText = null;
    else {
      defaultText = new StyledString(dtext, wrapWidth);
      defaultText.addAttribute(G4P.POSTURE, G4P.POSTURE_OBLIQUE);
    }
    bufferInvalid = true;
  }

  /**
   * Set the text to be used. The wrap width is determined by the size
   * of the control.
   * @param text
   */
  public void setText(String text){
    //setText(text, wrapWidth);
    setStyledText(new StyledString(text, wrapWidth));
  }

  /**
   * Set the text to display and adjust any scrollbars
   * @param text
   * @param wrapWidth
   */
  public void setText(String text, int wrapWidth){
    this.wrapWidth = wrapWidth;
    setStyledText(new StyledString(text, wrapWidth));
  }

  public void setStyledText(StyledString st){
    stext = st;
    if(stext.getWrapWidth() == Integer.MAX_VALUE)
      stext.setWrapWidth(wrapWidth);
    else
      wrapWidth = stext.getWrapWidth();
    stext.getLines(buffer.g2);
    if(stext.getNbrLines() > 0){
   
      // Ray: modify endTLHK.tli to set the cursor on the
      //      newly added line.
      //endTLHI.tli = stext.getLines(buffer.g2).getFirst();
      endTLHI.tli = stext.getLines(buffer.g2).getLast();
     
      endTLHI.thi = endTLHI.tli.layout.getNextLeftHit(1);
      startTLHI.copyFrom(endTLHI);
      calculateCaretPos(endTLHI);
      keepCursorInView = true;
    }
    ptx = pty = 0;
    float sTextHeight;
    if(vsb != null){
      sTextHeight = stext.getTextAreaHeight();
      if(sTextHeight < th)
        vsb.setValue(0.0f, 1.0f);
      else
        vsb.setValue(0, th/sTextHeight);
    }
    // If needed update the horizontal scrollbar
    if(hsb != null){
      if(stext.getMaxLineLength() < tw)
        hsb.setValue(0,1);
      else
        hsb.setValue(0, tw/stext.getMaxLineLength());
    }
    bufferInvalid = true;       
  }
 
  /**
   * Add text to the end of the current text. This is useful for a logging' type activity.
   *
   * @param extraText the text to append
   */
  public void appendText(String extraText){
    if(extraText == null || extraText.equals(""))
      return;
     
    // Ray: avoid inserting a new line when calling appendText
    //if(stext.insertCharacters(stext.length(), extraText, true) == 0)     
    if(stext.insertCharacters(stext.length(), extraText, false) == 0)
      return;
   
    LinkedList<TextLayoutInfo> lines = stext.getLines(buffer.g2);
    endTLHI.tli = lines.getLast();
   
    // Ray: modify endTLHI.thi to set cursor to the beginning of the new line
    //endTLHI.thi = endTLHI.tli.layout.getNextRightHit(endTLHI.tli.nbrChars - 1);
    endTLHI.thi = endTLHI.tli.layout.getNextLeftHit(1);
   
    startTLHI.copyFrom(endTLHI);
    calculateCaretPos(endTLHI);
    if(vsb != null){
      float vfiller = Math.min(1, th/stext.getTextAreaHeight());
      vsb.setValue(1 - vfiller, vfiller);
      keepCursorInView = true;
    }
    // If needed update the horizontal scrollbar
    if(hsb != null){
      float hvalue = lines.getLast().layout.getVisibleAdvance();
      float hlinelength = stext.getMaxLineLength();
      float hfiller = Math.min(1, tw/hlinelength);
      if(caretX < tw)
        hsb.setValue(0,hfiller);
      else
        hsb.setValue(hvalue/hlinelength, hfiller);
      keepCursorInView = true;
    }
    bufferInvalid = true;
  }

  /**
   * Add text to the end of the current text. This is useful for a logging' type activity.
   *
   * @param extraText the text to append
   */
//  public void appendText(String extraText){
//    appendText(extraText, false);
//  }
 
  /**
   * If the buffer is invalid then redraw it.
   */
  protected void updateBuffer(){
    if(bufferInvalid) {
      Graphics2D g2d = buffer.g2;
      // Get the latest lines of text
      LinkedList<TextLayoutInfo> lines = stext.getLines(g2d);
      if(lines.isEmpty() && defaultText != null)
        lines = defaultText.getLines(g2d);
       
      bufferInvalid = false;

      TextLayoutHitInfo startSelTLHI = null, endSelTLHI = null;
      buffer.beginDraw();
      // Whole control surface if opaque
      if(opaque)
        buffer.background(palette[6]);
      else
        buffer.background(buffer.color(255,0));

      // Now move to top left corner of text display area
      buffer.translate(tx,ty);

      // Typing area surface
      buffer.noStroke();
      buffer.fill(palette[7]);
      buffer.rect(-1,-1,tw+2,th+2);

      g2d.setClip(gpTextDisplayArea);
      buffer.translate(-ptx, -pty);
      // Translate in preparation for display selection and text
      if(hasSelection()){
        if(endTLHI.compareTo(startTLHI) == -1){
          startSelTLHI = endTLHI;
          endSelTLHI = startTLHI;
        }
        else {
          startSelTLHI = startTLHI;
          endSelTLHI = endTLHI;
        }
      } 

      // Display selection and text
      for(TextLayoutInfo lineInfo : lines){
        TextLayout layout = lineInfo.layout;
        buffer.translate(0, layout.getAscent());
        // Draw selection if any
        if(hasSelection() && lineInfo.compareTo(startSelTLHI.tli) >= 0 && lineInfo.compareTo(endSelTLHI.tli) <= 0 ){       
          int ss = 0;
          ss = (lineInfo.compareTo(startSelTLHI.tli) == 0) ? startSelTLHI.thi.getInsertionIndex()  : 0;
          int ee = endSelTLHI.thi.getInsertionIndex();
          ee = (lineInfo.compareTo(endSelTLHI.tli) == 0) ? endSelTLHI.thi.getInsertionIndex() : lineInfo.nbrChars-1;
          g2d.setColor(jpalette[14]);
          Shape selShape = layout.getLogicalHighlightShape(ss, ee);
          g2d.fill(selShape);
        }
        // display text
        g2d.setColor(jpalette[2]);
        lineInfo.layout.draw(g2d, 0, 0);
        buffer.translate(0, layout.getDescent() + layout.getLeading());
      }
      g2d.setClip(null);
      buffer.endDraw();
    }
  }

  public void pre(){
    if(keepCursorInView){
      boolean horzScroll = false, vertScroll = false;
      float max_ptx = caretX - tw + 2;
      float max_pty = caretY - th + 2 * stext.getMaxLineHeight();
     
      if(endTLHI != null){
        if(ptx > caretX){                     // LEFT?
          ptx -= HORZ_SCROLL_RATE;
          if(ptx < 0) ptx = 0;
          horzScroll = true;
        }
        else if(ptx < max_ptx){             // RIGHT?
          ptx += HORZ_SCROLL_RATE;
          if(ptx > max_ptx) ptx = max_ptx;
          horzScroll = true;
        }
        if(pty > caretY){                    // UP?
          pty -= VERT_SCROLL_RATE;
          if(pty < 0) pty = 0;
          vertScroll = true;
        }
        else if(pty < max_pty){  // DOWN?
          pty += VERT_SCROLL_RATE;
          vertScroll = true;
        }
        if(horzScroll && hsb != null)
          hsb.setValue(ptx / (stext.getMaxLineLength() + 4));
        if(vertScroll && vsb != null)
          vsb.setValue(pty / (stext.getTextAreaHeight() + 1.5f * stext.getMaxLineHeight()));
      }
      // If we have scrolled invalidate the buffer otherwise forget it
      if(horzScroll || vertScroll)
        bufferInvalid = true;
      else
        keepCursorInView = false;
    }
  }

  public void draw(){
    if(!visible) return;

    // Update buffer if invalid
    updateBuffer();
    winApp.pushStyle();

    winApp.pushMatrix();
    // Perform the rotation
    winApp.translate(cx, cy);
    winApp.rotate(rotAngle);

    winApp.pushMatrix();
    // Move matrix to line up with top-left corner
    winApp.translate(-halfWidth, -halfHeight);
    // Draw buffer
    winApp.imageMode(PApplet.CORNER);
    if(alphaLevel < 255)
      winApp.tint(TINT_FOR_ALPHA, alphaLevel);
    winApp.image(buffer, 0, 0);
   
    // Draw caret if text display area
    if(focusIsWith == this && showCaret && endTLHI != null){
      float[] cinfo = endTLHI.tli.layout.getCaretInfo(endTLHI.thi);
      float x_left =  - ptx + cinfo[0];
      float y_top = - pty + endTLHI.tli.yPosInPara;
      float y_bot = y_top - cinfo[3] + cinfo[5];
      if(x_left >= 0 && x_left <= tw && y_top >= 0 && y_bot <= th){
        winApp.strokeWeight(1.9f);
        winApp.stroke(palette[15]);
        winApp.line(tx+x_left, ty+Math.max(0, y_top), tx+x_left, ty+Math.min(th, y_bot));
      }
    }
   
    winApp.popMatrix();
    // Draw scrollbars
    if(children != null){
      for(GAbstractControl c : children)
        c.draw();
    }
    winApp.popMatrix();
    winApp.popStyle();
  }

  public PGraphics getSnapshot(){
    updateBuffer();
    PGraphicsJava2D snap = (PGraphicsJava2D) winApp.createGraphics(buffer.width, buffer.height, PApplet.JAVA2D);
    snap.beginDraw();
    snap.image(buffer,0,0);
    if(hsb != null){
      snap.pushMatrix();
      snap.translate(hsb.getX(), hsb.getY());
      snap.image(hsb.getBuffer(), 0, 0);
      snap.popMatrix();
    }
    if(vsb != null){
      snap.pushMatrix();
      snap.translate(vsb.getX(), vsb.getY());
      snap.rotate(PApplet.PI/2);
      snap.image(vsb.getBuffer(), 0, 0);
      snap.popMatrix();
    }
    snap.endDraw();
    return snap;
  }

  protected void keyPressedProcess(int keyCode, char keyChar, boolean shiftDown, boolean ctrlDown){
    boolean validKeyCombo = true;

    switch(keyCode){
    case LEFT:
      moveCaretLeft(endTLHI);
      break;
    case RIGHT:
      moveCaretRight(endTLHI);
      break;
    case UP:
      moveCaretUp(endTLHI);
      break;
    case DOWN:
      moveCaretDown(endTLHI);
      break;
    case GConstants.HOME:
      if(ctrlDown)    // move to start of text
        moveCaretStartOfText(endTLHI);
      else   // Move to start of line
        moveCaretStartOfLine(endTLHI);
      break;
    case GConstants.END:
      if(ctrlDown)    // move to end of text
        moveCaretEndOfText(endTLHI);
      else   // Move to end of line
        moveCaretEndOfLine(endTLHI);
      break;
    case 'A':
      if(ctrlDown){
        moveCaretStartOfText(startTLHI);
        moveCaretEndOfText(endTLHI);
        // Make shift down so that the start caret position is not
        // moved to match end caret position.
        shiftDown = true;
      }
      break;
    case 'C':
      if(ctrlDown)
        GClip.copy(getSelectedText());
      validKeyCombo = false;
      break;
    case 'V':
      if(ctrlDown){
        String p = GClip.paste();
        if(p.length() > 0){
          // delete selection and add
          if(hasSelection())
            stext.deleteCharacters(pos, nbr);
          stext.insertCharacters(pos, p);
          adjust = p.length();
          textChanged = true;
        }
      }
      break;
    default:
      validKeyCombo = false;
    }

    if(validKeyCombo){
      calculateCaretPos(endTLHI);
      //****************************************************************
      // If we have moved  to the end of a paragraph marker
      if(caretX > stext.getWrapWidth()){
        switch(keyCode){
        case LEFT:
        case UP:
        case DOWN:
        case END:
          moveCaretLeft(endTLHI);
          validKeyCombo = true;
          break;
        case RIGHT:
          if(!moveCaretRight(endTLHI))
            moveCaretLeft(endTLHI);
          validKeyCombo = true;
        }
        // Calculate new caret position
        // calculateCaretPos(startTLHI);
        calculateCaretPos(endTLHI);
      }
      //****************************************************************
     
      calculateCaretPos(endTLHI)

      if(!shiftDown)
        startTLHI.copyFrom(endTLHI);
      bufferInvalid = true;
    }
  }

  protected void keyTypedProcess(int keyCode, char keyChar, boolean shiftDown, boolean ctrlDown){
    int ascii = (int)keyChar;

    if(ascii >= 32 && ascii < 127){
      if(hasSelection())
        stext.deleteCharacters(pos, nbr);
      stext.insertCharacters(pos, "" + keyChar);
      adjust = 1; textChanged = true;
    }
    else if(keyChar == BACKSPACE){
      if(hasSelection()){
        stext.deleteCharacters(pos, nbr);
        adjust = 0; textChanged = true;       
      }
      else if(stext.deleteCharacters(pos - 1, 1)){
        adjust = -1; textChanged = true;
      }
    }
    else if(keyChar == DELETE){
      if(hasSelection()){
        stext.deleteCharacters(pos, nbr);
        adjust = 0; textChanged = true;       
      }
      else if(stext.deleteCharacters(pos, 1)){
        adjust = 0; textChanged = true;
      }
    }
    else if(keyChar == ENTER || keyChar == RETURN) {
      if(stext.insertEOL(pos)){
        adjust = 1; textChanged = true;
        newline = true;
      }
    }
    else if(keyChar == TAB){
      // If possible move to next text control
      if(tabManager != null){
        boolean result = (shiftDown) ? tabManager.prevControl(this) : tabManager.nextControl(this);
        if(result){
          startTLHI.copyFrom(endTLHI);
          return;
        }
      }
    }
    // If we have emptied the text then recreate a one character string (space)
    if(stext.length() == 0){
      stext.insertCharacters(0, " ");
      adjust++; textChanged = true;
    }
  }
  /**
   * Move caret to home position
   * @return true if caret moved else false
   */
  protected boolean moveCaretStartOfLine(TextLayoutHitInfo currPos){
    if(currPos.thi.getCharIndex() == 0)
      return false; // already at start of line
    currPos.thi = currPos.tli.layout.getNextLeftHit(1);
    return true;
  }

  protected boolean moveCaretEndOfLine(TextLayoutHitInfo currPos){
    if(currPos.thi.getCharIndex() == currPos.tli.nbrChars - 1)
      return false; // already at end of line
    currPos.thi = currPos.tli.layout.getNextRightHit(currPos.tli.nbrChars - 1);
    return true;
  }

  protected boolean moveCaretStartOfText(TextLayoutHitInfo currPos){
    if(currPos.tli.lineNo == 0 && currPos.thi.getCharIndex() == 0)
      return false; // already at start of text
    currPos.tli = stext.getTLIforLineNo(0);
    currPos.thi = currPos.tli.layout.getNextLeftHit(1);
    return true;
  }

  protected boolean moveCaretEndOfText(TextLayoutHitInfo currPos){
    if(currPos.tli.lineNo == stext.getNbrLines() - 1 && currPos.thi.getCharIndex() == currPos.tli.nbrChars - 1)
      return false; // already at end of text
    currPos.tli = stext.getTLIforLineNo(stext.getNbrLines() - 1);   
    currPos.thi = currPos.tli.layout.getNextRightHit(currPos.tli.nbrChars - 1);
    return true;
  }

  protected boolean moveCaretUp(TextLayoutHitInfo currPos){
    if(currPos.tli.lineNo == 0)
      return false;
    TextLayoutInfo ntli = stext.getTLIforLineNo(currPos.tli.lineNo - 1)
    TextHitInfo nthi = ntli.layout.hitTestChar(caretX, 0);
    currPos.tli = ntli;
    currPos.thi = nthi;
    return true;
  }

  protected boolean moveCaretDown(TextLayoutHitInfo currPos){
    if(currPos.tli.lineNo == stext.getNbrLines() - 1)
      return false;
    TextLayoutInfo ntli = stext.getTLIforLineNo(currPos.tli.lineNo + 1)
    TextHitInfo nthi = ntli.layout.hitTestChar(caretX, 0);
    currPos.tli = ntli;
    currPos.thi = nthi;
    return true;
  }

  /**
   * Move caret left by one character. If necessary move to the end of the line above
   * @return true if caret was moved else false
   */
  protected boolean moveCaretLeft(TextLayoutHitInfo currPos){
    TextLayoutInfo ntli;
    TextHitInfo nthi = currPos.tli.layout.getNextLeftHit(currPos.thi);
    if(nthi == null){
      // Move the caret to the end of the previous line
      if(currPos.tli.lineNo == 0)
        // Can't goto previous line because this is the first line
        return false;
      else {
        // Move to end of previous line
        ntli = stext.getTLIforLineNo(currPos.tli.lineNo - 1);
        nthi = ntli.layout.getNextRightHit(ntli.nbrChars-1);
        currPos.tli = ntli;
        currPos.thi = nthi;
      }
    }
    else {
      // Move the caret to the left of current position
      currPos.thi = nthi;
    }
    return true;
  }

  /**
   * Move caret right by one character. If necessary move to the start of the next line
   * @return true if caret was moved else false
   */
  protected boolean moveCaretRight(TextLayoutHitInfo currPos){
    TextLayoutInfo ntli;
    TextHitInfo nthi = currPos.tli.layout.getNextRightHit(currPos.thi);
    if(nthi == null){
      // Move the caret to the start of the next line the previous line
      if(currPos.tli.lineNo >= stext.getNbrLines() - 1)
        // Can't goto next line because this is the last line
        return false;
      else {
        // Move to start of next line
        ntli = stext.getTLIforLineNo(currPos.tli.lineNo + 1);
        nthi = ntli.layout.getNextLeftHit(1);
        currPos.tli = ntli;
        currPos.thi = nthi;
      }
    }
    else {
      // Move the caret to the right of current position
      currPos.thi = nthi;
    }
    return true;
  }

  /**
   * Will respond to mouse events.
   */
  public void mouseEvent(MouseEvent event){
    if(!visible  || !enabled || !available) return;

    calcTransformedOrigin(winApp.mouseX, winApp.mouseY);
    ox -= tx; oy -= ty; // Remove translation

    currSpot = whichHotSpot(ox, oy);

    if(currSpot == 1 || focusIsWith == this)
      cursorIsOver = this;
    else if(cursorIsOver == this)
      cursorIsOver = null;

    switch(event.getAction()){
    case MouseEvent.PRESS:
      if(currSpot == 1){
        if(focusIsWith != this && z >= focusObjectZ()){
          keepCursorInView = true;
          takeFocus();
        }
        dragging = false;
        if(stext == null || stext.length() == 0){
          stext = new StyledString(" ", wrapWidth);
          stext.getLines(buffer.g2);
        }
        endTLHI = stext.calculateFromXY(buffer.g2, ox + ptx, oy + pty);
        startTLHI = new TextLayoutHitInfo(endTLHI);
        calculateCaretPos(endTLHI);
        bufferInvalid = true;
      }
      else { // Not over this control so if we have focus loose it
        if(focusIsWith == this)
          loseFocus(null);
      }
      break;
    case MouseEvent.RELEASE:
      dragging = false;
      bufferInvalid = true;
      break;
    case MouseEvent.DRAG:
      if(focusIsWith == this){
        keepCursorInView = true;
        dragging = true;
        endTLHI = stext.calculateFromXY(buffer.g2, ox + ptx, oy + pty);
        calculateCaretPos(endTLHI);
        fireEvent(this, GEvent.SELECTION_CHANGED);
        bufferInvalid = true;
      }
      break;
    }
  }

  protected void calculateCaretPos(TextLayoutHitInfo tlhi){
    float temp[] = tlhi.tli.layout.getCaretInfo(tlhi.thi);
    caretX = temp[0];   
    caretY = tlhi.tli.yPosInPara;
  }



}
TOP

Related Classes of g4p_controls.GTextArea

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.